﻿// -------------------------------------------------------------------------- //
//	文件名		: 	ET_Improve\CEtOP.cs
//	创建者		:	xianglinjian
//	创建时间	:	2010-10-20   18:00:43
//	功能描述	:   ET的所有操作都放在这里
//
// -------------------------------------------------------------------------- //
#if ENABLE_ET_COM
#define ENABLE_AutoItX
namespace etOp
{
    using System;
    using System.Timers;
    using ET;
    using Microsoft.Win32;

    public class EtOp
    {
        protected Application m_app;
        protected Workbooks m_workbooks;
        protected _Workbook m_workbook;

        protected string m_sFilePassword;
        protected int m_nCurEtPid;
        protected static readonly object MISS_VALUE = System.Reflection.Missing.Value;
        public string m_sCurFileName;
        protected tool.CTimer m_timer;
        private autoIt.CAutoIt m_wndKiller;

        // 如果不想使用AutoIt关闭对话框则_killWndTool置null
        public void Init(autoIt.CAutoIt _killWndTool, bool bOpenTime)
        {
            if (_killWndTool != null)
            {
                m_wndKiller = _killWndTool;
                m_wndKiller.AddBlockFunc(DoShellBlock);
            }
            if (bOpenTime)
            {
                m_timer = new tool.CTimer(KillCurApp);
            }
        }

        public static void DestoryET(ref EtOp pET)
        {
            if(pET != null)
            {
                pET.Close();
                pET = null;
            }
        }

        protected void KillCurApp()
        {
            System.Diagnostics.Process pEt = System.Diagnostics.Process.GetProcessById(m_nCurEtPid);
            pEt.Kill();
            m_nCurEtPid = -1;
        }


        public void DoShellBlock(bool bUnknown)
        {
            try
            {
                if(bUnknown)    //  如果是unknown已经在CAutoIt中kill了
                {
                    m_workbook = null;
                    m_workbooks = null;
                    m_app = null;
                    tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.SHELL_BLOCK, m_sCurFileName,
                        "program is blocked by unknown reason.", null);
                }
                else
                {
                    Close();
                    tool.CAddInfoHlp.AddFileIgnore(m_sCurFileName, ET_Improve.Global.s_curCmdName,
                        tool.LogTool.LOG_TYPE.SHELL_BLOCK);
                }
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName,
                    "Failed of calling DoShellBlock function", ex);
            }
        }

        public void Create()
        {
            try
            {
                if (m_app == null)
                {
                    GetNewEt();
                }
                m_workbook = m_app.Workbooks.Add(MISS_VALUE);
            }
            catch (System.Exception ex)
            {
                throw new tool.ETImpException(tool.LogTool.LOG_TYPE.ERROR, null, "Failed of Create ET", ex);
            }
        }

        // 没有密码就传null
        public void Open(string sFileName, string sPassword)
        {
            GetNewEt();
            m_app.Visible = false;
            m_workbooks = m_app.Workbooks;
            m_sCurFileName = sFileName;
            m_sFilePassword = sPassword;

            if (m_timer != null)
            {
                m_timer.BeginTimer(ET_Improve.Global.gTimeOut * 60, false);
            }
            try
            {
                m_workbook = m_workbooks.Open(
                       sFileName,   // filename 
                       0,           // UpdateLinks
                       true,       // ReadOnly
                       MISS_VALUE,   // Format
                       (m_sFilePassword == null) ? MISS_VALUE : m_sFilePassword, // Password
                       MISS_VALUE,   // Write Res Value Password
                       MISS_VALUE,   // IgnoreReadonlyRecommended
                       MISS_VALUE,   // Origin
                       MISS_VALUE,   // Delimiter
                       false,       // Editable
                       false,       // Nofify
                       MISS_VALUE,   // Converter
                       false        // AddToMru
                       );
                m_workbook.EnableAutoFit = false;
            }
            catch (System.Exception ex)
            {
                if (m_wndKiller != null && m_wndKiller.IsNeedPassword())
                {
                    m_wndKiller.ResetWndInfo();
                    throw new tool.ETImpException(tool.LogTool.LOG_TYPE.NO_PASSWORD, sFileName, "ET");
                }
                else if (m_timer != null && m_timer.IsTimeOut())
                {
                    throw new tool.ETImpException(tool.LogTool.LOG_TYPE.TIME_OUT, sFileName, "ET");
                }
                else
                {
                    throw new tool.ETImpException(tool.LogTool.LOG_TYPE.OPEN_FAILED, sFileName, "ET", ex);
                }
            }
            finally
            {
                if (m_timer != null)
                {
                    m_timer.EndTimer();
                }
            }
        }

        public void RecalcAll()
        {
            try
            {
                m_app.DebugTools.RunCommand(7, "FA3BFF9AB1D44f86A15213DFEB25D4E9", MISS_VALUE, MISS_VALUE);
            }
            catch (Exception ex)
            {
                throw new tool.ETImpException(tool.LogTool.LOG_TYPE.ERROR, m_sCurFileName, "DebugTools", ex);
            }
        }


        public String[] GetSheetName()
        {
            Worksheets _worksheets = m_app.Worksheets;
            int nCount = _worksheets.Count;
            String[] names = new String[nCount];
            for(int i = 0; i < nCount; ++i)
            {
                Worksheet _worksheet = (Worksheet)_worksheets[i + 1];
                names[i] = _worksheet.Name;
                NAR(_worksheet);
            }
            NAR(_worksheets);

            return names;
        }

        // 不要抛出异常
        public void Close()
        {
            try
            {
                ReleaseWorkbook();
                NAR(m_workbooks);
                ReleaseApp();
            }
            catch (System.Exception ex) //  此处的异常可能是无关紧要的
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.EXCEPTION, null, "ET.Close 可能是无关紧要的异常" + ex.Message, null);
                EtOp.KillAllEtProcess();
            }
        }

        public string SaveAsTmpFile()
        {
            string sTmpFile = tool.CTmpFileHlp.GetSystemTmpName(m_sCurFileName);
            SaveAsFile(sTmpFile);
            return sTmpFile;
        }

        public void SaveAsFile(string dstFile)
        {
            try
            {
                m_workbook.SaveAs(dstFile, MISS_VALUE,
                    (m_sFilePassword == null) ? MISS_VALUE : m_sFilePassword,
                    MISS_VALUE, MISS_VALUE, false, ETSaveAsAccessMode.etNoChange,
                    false, MISS_VALUE, MISS_VALUE, MISS_VALUE);
                tool.Output.DebugWriteLine(">SaveAs<");
            }
            catch (Exception ex)
            {
                throw new tool.ETImpException(tool.LogTool.LOG_TYPE.ERROR, dstFile, "ET另存临时文件失败:", ex);
            }
        }

        protected bool IsStable()
        {
            System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById(m_nCurEtPid);
            // 比较两秒前后CPU时间是否变化
            long m1 = proc.WorkingSet64 / 1024;
            int t1 = proc.TotalProcessorTime.Seconds;
            System.Threading.Thread.Sleep(2000);
            long m2 = proc.WorkingSet64 / 1024;
            int t2 = proc.TotalProcessorTime.Seconds;

            if (t1 != t2)
            {
                return false;
            }

            return true;
        }

        public void GetCurEtPid()
        {
            try
            {
                System.Diagnostics.Process[] processes =
                    System.Diagnostics.Process.GetProcessesByName("et");
                int[] pids = new int[processes.Length];
                for (int i = 0; i < processes.Length; ++i)
                {
                    pids[i] = processes[i].Id;
                }
                Array.Sort(pids);
                m_app = new Application();
                m_app.Visible = false;

                System.Diagnostics.Process[] procs =
                        System.Diagnostics.Process.GetProcessesByName("et");
                for (int k = 0; k < procs.Length; ++k)
                {
                    int nFind = Array.BinarySearch(pids, procs[k].Id);
                    if (nFind < 0)
                    {
                        m_nCurEtPid = procs[k].Id;
                        return;
                    }
                }
                throw new Exception("获取ET进程PID失败");
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
        }

        public static void KillAllEtProcess()
        {

            System.Diagnostics.Process[] processes =
                    System.Diagnostics.Process.GetProcessesByName("et");
            foreach (System.Diagnostics.Process proc in processes)
            {
                proc.Kill();
            }

        }

        public void Calculate()
        {
            m_app.Calculate();
        }

        public bool GetTimeMemory(ref int nTm, ref long lMem)
        {
            if(m_nCurEtPid < 0)
            {
                return false;
            }

            System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById(m_nCurEtPid);
            nTm = proc.TotalProcessorTime.Seconds;
            lMem = proc.WorkingSet64 / 1024;
            return true;
        }

        public static void ReRegisterET(string _appPath)
        {
            const string CSLID_VALUE = "{45540001-5750-5300-4B49-4E47534F4654}";
            const string CSLID_ITEM = "CLSID";
            const string LS32_ITEM = "LocalServer32";
            try
            {
                string sValue = _appPath + "\\et.exe /Automation";
                RegistryKey hKey = Registry.ClassesRoot;
                hKey = hKey.OpenSubKey(CSLID_ITEM);
                hKey = hKey.OpenSubKey(CSLID_VALUE);
                hKey = hKey.OpenSubKey(LS32_ITEM, true);
                hKey.SetValue(null, sValue);
            }
            catch (System.Exception ex)
            {
	            throw ex;
            }
        }

        // 超过10个则kill all
        protected int[] PreCreateNewEt()
        {
            System.Diagnostics.Process[] processes =
             System.Diagnostics.Process.GetProcessesByName("et");
            if(processes.Length >= 10)
            {
                foreach (System.Diagnostics.Process p in processes)
                {
                    p.Kill();
                }
                return null;
            }

            int[] pids = new int[processes.Length];
            for (int i = 0; i < processes.Length; ++i)
            {
                pids[i] = processes[i].Id;
            }
            Array.Sort(pids);
            return pids;
        }

        public void GetNewEt()
        {
            try
            {
                int[] pids = PreCreateNewEt();
                m_app = new Application();
                if(pids == null)
                {
                    return;
                }
                
                System.Diagnostics.Process[] procs =
                        System.Diagnostics.Process.GetProcessesByName("et");
                for (int k = 0; k < procs.Length; ++k)
                {
                    int nFind = Array.BinarySearch(pids, procs[k].Id);
                    if (nFind < 0)
                    {
                        m_nCurEtPid = procs[k].Id;
                        return;
                    }
                }
                throw new Exception("获取ET进程PID失败");
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
        } 

        //-------------------------------------------------------------------------------------------
        public static ET.Application GainNewInstance(int nCntInitBook, bool bVisible)
        {
            ET.Application app = new ET.Application();
            app.Visible = bVisible;
            app.DisplayAlerts = false;

            for (int i = 0; i < nCntInitBook; ++i)
            {
                app.Workbooks.Add(MISS_VALUE);
            }

            while (app.Workbooks.Count > nCntInitBook)
            {
                app.Workbooks.get_Item(1).Close(false, MISS_VALUE, MISS_VALUE);
            }

            return app;
        }

        public static void CloseAndClean(ref ET.Application app)
        {
            while (app.Workbooks.Count > 0)
            {
                app.Workbooks.get_Item(1).Close(false, MISS_VALUE, MISS_VALUE);
            }

            app.Quit();
            System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
            app = null;

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        public static ET.Range SingeBookAppGetRange(
            ET.Application app, Int32 nSheetBase0, String strCell)
        {
            return SingeBookAppGetRange(app, nSheetBase0, strCell, strCell);
        }

        public static ET.Range SingeBookAppGetRange(
            ET.Application app, Int32 nSheetBase0,
            String strLT_Cell, String strRB_Cell)
        {
            ET._Worksheet wkSht = (ET._Worksheet)app.Workbooks.get_Item(1
                ).Worksheets.get_Item(nSheetBase0 + 1);

            return wkSht.get_Range(strLT_Cell, strRB_Cell);
        }

        protected void ReleaseWorkbook()
        {
            if (m_workbook == null)
            {
                return;
            }
            try
            {
                m_workbook.Saved = true;    //  不显示保存对话框
                m_workbook.Close(false, null, null);
            }
            catch { }
            finally
            {
                NAR(m_workbook);
            }
        }

        protected void ReleaseApp()
        {
            if (m_app == null)
            {
                return;
            }
            try
            {
                m_app.Quit();
            }
            catch
            {

            }
            finally
            {
                NAR(m_app);
            }
        }

        protected static void NAR(object o)
        {
            if (o == null)
            {
                return;
            }

            try
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
            }
            catch { }
            finally
            {
                o = null;
            }
        }
    }
}


#endif // #if ENABLE_ET_COM